home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 7 / Amiga Format AFCD07 (Dec 1996, Issue 91).iso / serious / shareware / programming / aros / alib / boopsi.c next >
Encoding:
C/C++ Source or Header  |  1996-09-12  |  12.7 KB  |  489 lines

  1. /*******************************************************************************
  2.  
  3.     MODUL
  4.     boopsi.c
  5.  
  6.     DESCRIPTION
  7.     Implementiert BOOPSI - Basic Object Oriented Programming System
  8.     for Intuition. BOOPSI gestattet C++-Methoden in Standard ANSI
  9.     bzw K&R-C zu verwenden. Die Vorgehensweise ist wie folgt:
  10.  
  11.         BOOPSI arbeitet mit sog. Message-Dispatchern. Ein Message
  12.     Dispatcher ist im Prinzip nichts anderes als eine Routine, die
  13.     Nachrichten an ein Object auswertet. Diese Nachricht ist nichts
  14.     anderes als eine Structur mit ID. Die ID bestimmt den Typ der
  15.     Nachricht (z.B. Setzte Attribute des Objects).
  16.  
  17.         Der Vorteil von BOOPSI liegt darin, dass die Zugriffsfunktionen
  18.     alle extern zum Object und standardisiert sind. Der Benutzer eines
  19.     Object muss sich nicht mehr viele verschiedene Funktionsnamen merken
  20.     sondern kann mit fuenf Funktionen alle Operationen auf Objecte
  21.     durchfuehren. Diese Operationen sind:
  22.  
  23.         - Erzeuge ein neues Object (eine neue Instanz des Objects)
  24.         - Loese ein Object auf
  25.         - Setze Attribute des Objects
  26.         - Frage Attribute des Objects ab
  27.         - Wende eine Methode auf das Object an.
  28.  
  29.     NOTES
  30.  
  31.     BUGS
  32.  
  33.     TODO
  34.  
  35.     EXAMPLES
  36.     // Beispiel eines kompletten Line-Objects
  37.  
  38.     // Hier wird die Instance-Data definiert. Der Speicher fuer diese
  39.     // Struktur wird vom Betriebssystem angelegt und verwaltet.
  40.     struct LineData
  41.     {
  42.         FLOAT coords[4];
  43.         ULONG width;
  44.         ULONG style;
  45.     };
  46.  
  47.     // In einem Include-File sind folgende Tags definiert:
  48.     //
  49.     //    LINE_StartX, (FLOAT, CSG)
  50.     //    LINE_StartY, (FLOAT, CSG)
  51.     //    LINE_EndX, (FLOAT, CSG)
  52.     //    LINE_EndY, (FLOAT, CSG)
  53.     //    LINE_Width, (INT, CSG)
  54.     //    LINE_Style, (INT, CSG)
  55.     //
  56.     // und folgende Methoden
  57.     //
  58.     //    LINEM_Display, (GC)
  59.     //
  60.     // Mit diesen lassen sich die einzelnen Attribute des Objects aendern
  61.  
  62.     // Initialisierung und Bekanntmachung des Objects
  63.     Class * initLineClass P((void))
  64.     {
  65.         Class * cl;
  66.  
  67.         // Neue Klasse mit dem Namen "lineclass" bekanntgeben und
  68.         // verschiedene Default-Werte initialisieren.
  69.         if (cl = MakeClass (NULL,
  70.             "lineclass", NULL,
  71.             sizeof (struct LineData),
  72.             0))
  73.         {
  74.         // Dispatcher eintragen. Unter UNIX muss bei h_Entry immer
  75.         // HookEntry stehen.
  76.         cl->cl_Dispatcher.h_Entry    = HookEntry;   // always for UNIX
  77.         cl->cl_Dispatcher.h_SubEntry = dispatchLineClass;
  78.         }
  79.     } // initLineClass
  80.  
  81.  
  82.     // Klasse wieder entfernen. Das muss man vor dem Verlassen
  83.     // des Programms tun, weil zB. unter AmigaOS alle Public-Objecte
  84.     // global bekannt sind und deshalb andere Programme u.U. noch
  85.     // auf das Object zugreifen.
  86.     BOOL freeLineClass (cl)
  87.     Class * cl;
  88.     {
  89.         return (FreeClass (cl));
  90.     } // freeLineClass
  91.  
  92.  
  93.     // Hier folgt jetzt der interessante Teil: Ein BOOSPI-Dispatcher.
  94.     // GETA4 ist unter UNIX leer, unter AmigaOS wird damit die lokale
  95.     // Umgebung (zB. Variablen initialisiert
  96.     __geta4 ULONG dispatchLineClass (cl, o, msg)
  97.     REG(A0) Class  * cl;
  98.     REG(A2) Object * o;
  99.     REG(A1) Msg      msg;
  100.     {
  101.         struct LineData * inst;        // instance data
  102.         APTR          retval = NULL;    // generic return value
  103.  
  104.         // Die Bedeutung von retval haengt von der verwendeten Methode
  105.         // ab. ZB. ist es bei OM_GET ein Boolean-Wert, bei OM_NEW aber
  106.         // ein Zeiger auf das neue Object
  107.  
  108.         switch (msg->MethodID)  // Welche Methode ?
  109.         {
  110.         case OM_NEW:    // Zuerst wird die Message nach "oben"
  111.                 // weitergegeben damit die Superclass
  112.                 // zuerst alles Einrichten kann (zB.
  113.                 // Speicher besorgen).
  114.  
  115.         if (retval = (APTR)DoSuperMethodA (cl, o, msg))
  116.         {
  117.             // Bei der OM_NEW-Methode zeigt der Object-Pointer nicht
  118.             // auf ein Object (wie auch ??). DoSuperMethod() gibt
  119.             // einen Zeiger auf das neu erzeugte Object zurueck.
  120.             // INST_DATA() ist ein Macro aus <intuition/classes.h>
  121.             // welches einen Zeiger auf die Instance-Data des Objects
  122.             // zurueckliefert. Dies ist hier die LineData-Struktur
  123.             // von oben.
  124.             //
  125.             //      Beachten Sie, dass der Speicher in keiner Weise
  126.             // vorinitialisiert wird !
  127.  
  128.             inst = INST_DATA(cl,retval);
  129.  
  130.             // Jetzt koennen wir alle Felder initalisieren. Das muss
  131.             // so getan werden, dass man gefahrlos ALLE Methoden auf
  132.             // das Object anwenden kann.
  133.  
  134.             inst->Width = 0;    // Breite = 0 -> Nichts tun
  135.  
  136.             // Wenn wir hier etwas komplizierteres machen wollten
  137.             // (zB. Kind-Objecte erzeugen) waere das ohne weiteres
  138.             // moeglich. Aber dann muss bei einem Fehler
  139.             // DoMethod (retval, OM_DISPOSE); aufgerufen werden !
  140.         }
  141.  
  142.         // Nur abbrechen, wenn kein Object erzeugt werden konnte.
  143.         // Sonst sollten wir noch die Start-Attribute abfragen !
  144.         if (!retval)
  145.             break;
  146.  
  147.         // Fuer weitere Schritte sollte <o> schon auf einen
  148.         // sinnvollen Wert zeigen :-)
  149.  
  150.         o = (Object *)retval;
  151.  
  152.         case OM_SET:    // Mit OM_SET kann man Attribute setzen.
  153.         case OM_UPDATE: // Wie OM_SET, nur kommt es von einem anderen
  154.                 // BOOPSI-Object !
  155.  
  156.         // Zuerst wieder die SuperClass ranlassen (nur, wenn nicht
  157.         // OM_NEW) damit diese zuerst alle ihr wichtigen Attribute
  158.         // bearbeiten kann.
  159.  
  160.         if (msg->MethodID != OM_NEW)
  161.             retval = DoSuperMethodA (cl, o, msg);
  162.  
  163.         // Jetzt sind wir dran
  164.  
  165.         {   // Fuer lokale Variable
  166.             struct TagItem * ti, * tstate;
  167.  
  168.             // Instance-Data raussuchen
  169.  
  170.             inst = INST_DATA(cl, o);
  171.  
  172.             // Tag-Liste untersuchen und Attribute kopieren
  173.             for (ti=tstate=((struct opSet *)msg)->ops_AttrList);
  174.                 ti; ti = NextTagItem (&tstate))
  175.             {
  176.             // Hier alle unbekannten Tags einfach ignorieren
  177.             // weil sie wahrscheinlich zu einer der Superklassen
  178.             // gehoeren
  179.             switch (ti->ti_Tag)
  180.             {
  181.             case LINE_StartX:
  182.                 *(&inst->coords[0]) = *(FLOAT *)ti->ti_Data;
  183.                 break;
  184.  
  185.             case LINE_StartY:
  186.                 *(&inst->coords[1]) = *(FLOAT *)ti->ti_Data;
  187.                 break;
  188.  
  189.             case LINE_EndX:
  190.                 *(&inst->coords[2]) = *(FLOAT *)ti->ti_Data;
  191.                 break;
  192.  
  193.             case LINE_EndY:
  194.                 *(&inst->coords[3]) = *(FLOAT *)ti->ti_Data;
  195.                 break;
  196.  
  197.             case LINE_Width:
  198.                 inst->Width = ti->ti_Data;
  199.                 break;
  200.  
  201.             case LINE_Style:
  202.                 inst->Style = ti->ti_Data;
  203.                 break;
  204.  
  205.             }
  206.             } // for
  207.         } // local block
  208.  
  209.         break; // OM_SET, OM_UPDATE
  210.  
  211.         case OM_GET: // ein (1!) Attribut lesen
  212.         inst = INST_DATA(cl, o);
  213.  
  214.         // Erst mal auf TRUE setzen -> Attribut gefunden.
  215.         // Wenn es ein Line-Attribut ist, wird es auf alle
  216.         // Faelle gefunden, wenn es ein Attribut der Superclass
  217.         // ist, wird der Wert nochmals bei DoSuperMethodA()
  218.         // gesetzt.
  219.  
  220.         retval = (APTR)TRUE;
  221.  
  222.         switch (((struct opGet *)msg)->opg_AttrID)
  223.         {
  224.         case LINE_StartX:
  225.             *((FLOAT *)(((struct opGet *)msg)->opg_Storage)) =
  226.                 inst->coords[0];
  227.             break;
  228.  
  229.         // usw. usf.
  230.  
  231.         default:
  232.             // Kein Attribut von uns ?? Dann lassen wir mal die
  233.             // Superclass ran
  234.             retval = DoSuperMethodA (cl, o, msg);
  235.         }
  236.  
  237.         break;     // OM_GET
  238.  
  239.         default: // Unbekannte Methode ? Vielleicht kann ja die
  240.              // Superclass was damit anfangen !
  241.  
  242.         // Hier wird in unserem Beispiel OM_DISPOSE behandelt.
  243.         // Sollten wir eine kompliziertere Version von OM_DISPOSE
  244.         // benoetigen, weil wir zB. Kinder freizugeben haben,
  245.         // muessten wird das VOR dem Aufruf von DoSuperMethodA()
  246.         // machen, weil danach der Zugriff auf das Object nicht
  247.         // mehr erlaubt ist.
  248.  
  249.         retval = DoSuperMethodA (cl, o, msg);
  250.         break;
  251.  
  252.         } // switch
  253.  
  254.         // Ergebnis zurueck
  255.         return (retval);
  256.     } // dispatchLineClass
  257.  
  258.     SEE ALSO
  259.  
  260.     INDEX
  261.  
  262.     HISTORY
  263.     14.09.93    ada created
  264.  
  265. *******************************************************************************/
  266.  
  267. /**************************************
  268.         Includes
  269. **************************************/
  270. #ifndef INTUITION_CLASSES_H
  271. #   include <intuition/classes.h>
  272. #endif
  273. #ifndef CLIB_ALIB_PROTOS_H
  274. #   include <clib/alib_protos.h>
  275. #endif
  276. #include <stdarg.h>
  277.  
  278.  
  279. static ULONG CallHookPkt (struct Hook * hook, APTR object, APTR paramPacket)
  280. {
  281.     return ((*(hook->h_Entry)) (hook, object, paramPacket));
  282. }
  283.  
  284. /******************************************************************************
  285.  
  286.     NAME */
  287.     ULONG DoMethodA (
  288.  
  289. /*  SYNOPSIS */
  290.     Object * obj,
  291.     Msg     message)
  292.  
  293. /*  FUNCTION
  294.     Wendet eine Methode auf ein BOOPSI-Object an. Dazu wird der Dispatcher
  295.     fuer die Klasse, der das Object angehoert aufgerufen. Die Methoden,
  296.     welche ein Object unterstuetzt, werden auf einer Klasse-fuer-Klasse
  297.     Basis definiert.
  298.  
  299.     INPUTS
  300.     obj - Das Object, auf welches sich die Operation bezieht.
  301.     message - Die Method-Message. Das erste ULONG der Message definiert den
  302.         Typ, der Rest haengt von der Klasse ab.
  303.  
  304.     RESULT
  305.     Der Rueckgabewert haengt von der Methode ab. Bei OM_NEW ist es z.B. ein
  306.     Zeiger auf das neu generierte Object; andere Methoden verwenden andere
  307.     Ergebnis-Werte. Diese werden bei der Beschreibung der Klasse definiert
  308.     und sind dort nachzulesen.
  309.  
  310.     NOTES
  311.  
  312.     EXAMPLE
  313.  
  314.     BUGS
  315.  
  316.     SEE ALSO
  317.     NewObject(), SetAttrs(), GetAttr(), DisposeObject(), DoSuperMethod(),
  318.     "Basic Object-Oriented Programming System for Intuition" und das
  319.     "boopsi Class Reference" Dokument.
  320.  
  321.     HISTORY:
  322.     14.09.93    ada created
  323.  
  324. ******************************************************************************/
  325. {
  326.     return (CallHookPkt ((struct Hook *)OCLASS(obj), obj, message));
  327. } /* DoMethodA */
  328.  
  329.  
  330. ULONG DoMethod (Object * obj, ULONG MethodID, ...)
  331. {
  332.     va_list args;
  333.     ULONG   retval;
  334.  
  335.     va_start (args, MethodID);
  336.  
  337.     retval = (CallHookPkt ((struct Hook *)OCLASS(obj), obj, (Msg)&MethodID));
  338.  
  339.     va_end (args);
  340.  
  341.     return (retval);
  342. } /* DoMethod */
  343.  
  344.  
  345. /******************************************************************************
  346.  
  347.     NAME
  348.     DoSuperMethodA -- Sende eine Message an die SuperClass eines Objects
  349.  
  350.     SYNOPSIS
  351.     retval = DoSuperMethodA (cl, obj, message)
  352.  
  353.     ULONG DoSuperMethodA (Class *, Object * obj, Msg message);
  354.  
  355.     retval = DoSuperMethod (class, obj, MethodID, ...)
  356.  
  357.     ULONG DoSuperMethod (Class *, Object * obj, ULONG MethodID, ...);
  358.  
  359.     FUNCTION
  360.     Sendet eine BOOPSI-Message an ein BOOPSI-Object als ob dieses eine
  361.     Instanz seiner SuperKlasse waere.
  362.  
  363.     INPUTS
  364.     cl - Class des Objects.
  365.     obj - Das Object, auf welches sich die Operation bezieht.
  366.     message - Die Method-Message. Das erste ULONG der Message definiert den
  367.         Typ, der Rest haengt von der Klasse ab.
  368.  
  369.     RESULT
  370.     Der Rueckgabewert haengt von der Methode ab. Bei OM_NEW ist es z.B. ein
  371.     Zeiger auf das neu generierte Object; andere Methoden verwenden andere
  372.     Ergebnis-Werte. Diese werden bei der Beschreibung der Klasse definiert
  373.     und sind dort nachzulesen.
  374.  
  375.     NOTES
  376.  
  377.     EXAMPLE
  378.  
  379.     BUGS
  380.  
  381.     SEE ALSO
  382.     NewObject(), SetAttrs(), GetAttr(), DisposeObject(), DoMethod(),
  383.     "Basic Object-Oriented Programming System for Intuition" und das
  384.     "boopsi Class Reference" Dokument.
  385.  
  386.     HISTORY:
  387.     14.09.93    ada created
  388.  
  389. ******************************************************************************/
  390.  
  391. ULONG DoSuperMethodA (cl, obj, message)
  392. Class  * cl;
  393. Object * obj;
  394. Msg     message;
  395. {
  396.     return (CallHookPkt ((struct Hook *)cl->cl_Super, obj, message));
  397. } /* DoSuperMethodA */
  398.  
  399.  
  400. ULONG DoSuperMethod (Class * cl, Object * obj, ULONG MethodID, ...)
  401. {
  402.     va_list args;
  403.     ULONG   retval;
  404.  
  405.     va_start (args,MethodID);
  406.  
  407.     retval = DoSuperMethodA (cl, obj, (Msg)&MethodID);
  408.  
  409.     va_end (args);
  410.  
  411.     return (retval);
  412. } /* DoSuperMethod */
  413.  
  414.  
  415. #ifdef TODO
  416. /******************************************************************************
  417.  
  418.     NAME
  419.     GetAttrsA
  420.  
  421.     SYNOPSIS
  422.     GetAttr (object, tags)
  423.  
  424.     void GetAttr (Object *, struct TagItem *);
  425.  
  426.     FUNCTION
  427.     Fragt bei dem angegebenen Objekt die angegebenen Attribut ab.
  428.  
  429.     Im ti_Data_feld der TagItem-Elemente werden Zeiger auf Langworte
  430.     erwartet. In diese wird der Wert des Attributs geschrieben.
  431.  
  432.     Nicht alle Attribute werden auf diese Attribute reagieren. Welche
  433.     das es tun steht bei der Dokumentation der Klasse.
  434.  
  435.     INPUTS
  436.     object - Das Objekt ueber dessen Attribut wir uns informieren wollen
  437.     tags - Gesuchtes Attribut und hier wird die Antwort reingeschrieben.
  438.  
  439.     RESULT
  440.     Keines.
  441.  
  442.     NOTES
  443.     Diese Funktion ruft die OM_GET-Methode fuer ein Objekt auf.
  444.  
  445.     EXAMPLE
  446.  
  447.     BUGS
  448.  
  449.     SEE ALSO
  450.     NewObject(), DisposeObject(), SetAttr(), GetAttrs(), MakeClass(),
  451.     "Basic Object-Oriented Programming System for Intuition" und das
  452.     "boopsi Class Reference" Dokument.
  453.  
  454.     HISTORY:
  455.     02.12.93    ada created
  456.  
  457. ******************************************************************************/
  458.  
  459. void GetAttrsA (object, tags)
  460. Object * object;
  461. struct TagItem * tags;
  462. {
  463.     struct TagItem * ti, * tstate;
  464.  
  465.     /* Fuer alle Attribute in der Liste GetAttr() aufrufen */
  466.     for (ti=tstate=tags; ti; ti = NextTagItem (&tstate))
  467.     {
  468.     GetAttr (ti->ti_Tag, object, (ULONG *) ti->ti_Data);
  469.     }
  470. } /* GetAttrsA */
  471.  
  472.  
  473. void GetAttrs (Object * obj, ...)
  474. {
  475.     va_list         args;
  476.  
  477.     va_start (args, obj);
  478.  
  479.     GetAttrsA (obj, (struct TagItem *)args);
  480.  
  481.     va_end (args);
  482. } /* GetAttrs */
  483. #endif
  484.  
  485.  
  486. /*******************************************************************************
  487. *****  ENDE boopsi.c
  488. *******************************************************************************/
  489.